//
//  MFAPMDataBase.m
//  MFAPMManager
//
//  Created by zhang liyu on 2019/5/29.
//

#import "MFAPMDataBase.h"

#import "MFAPMUtility.h"

#if __has_include(<fmdb/FMDB.h>)
#import <fmdb/FMDB.h>
#else
#import "FMDB.h"
#endif

#define kMFAPMDataBaseCreateSQL @"CREATE TABLE IF NOT EXISTS MFAPM_DataTable ('timestamp' DOUBLE UNIQUE PRIMARY KEY, 'eventType' DOUBLE NOT NULL, 'param' TEXT NOT NULL)"
#define kMFAPMDataBaseInsertSQL @"INSERT INTO MFAPM_DataTable (timestamp, eventType, param) VALUES (%@, %@, %@)"
#define kMFAPMDataBaseDeleteAllDataSQL @"DELETE FROM MFAPM_DataTable"
#define kMFAPMDataBaseDeletePreNUMItemSQL @"DELETE FROM MFAPM_DataTable WHERE (SELECT COUNT(timestamp) FROM MFAPM_DataTable)> %@ AND timestamp IN (SELECT timestamp FROM MFAPM_DataTable ORDER BY timestamp ASC LIMIT %@);"
#define kMFAPMDataBaseQueryAllItemsOrderSQL @"SELECT * FROM MFAPM_DataTable ORDER BY timestamp %@"
#define kMFAPMDataBaseQueryCountSQL @"SELECT COUNT(*) FROM MFAPM_DataTable"

static BOOL isDBDealloc = NO;
static BOOL isTableCreate = NO;
@interface MFAPMDataBase()

@property (nonatomic, strong) FMDatabase *db;
@property (nonatomic, strong) FMDatabaseQueue *dbQuque;
@property (nonatomic, copy) NSString *dbPath;

@end

@implementation MFAPMDataBase

#pragma mark - Singleton

+ (instancetype)sharedInstance{
    static MFAPMDataBase *dataBase = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dataBase = [[MFAPMDataBase alloc] init];
    });
    return dataBase;
}

#pragma mark - Life Circle

- (instancetype)init{
    self = [super init];
    if(self){
        [self installActions];
    }
    return self;
}

- (void)installActions{
    
    isDBDealloc = NO;
    isTableCreate = NO;
    
    //创建表
    [self.dbQuque inTransaction:^(FMDatabase *db, BOOL *rollback) {
        if(![db executeUpdate:kMFAPMDataBaseCreateSQL]){
            *rollback = YES;
        }else{
            isTableCreate = YES;
        }
    }];
}

#pragma mark - DataBase Control Actions

+ (void)closeDB{
    if(isDBDealloc){
        return;
    }
    isDBDealloc = YES;
    
    [[MFAPMDataBase sharedInstance].db close];
    [[MFAPMDataBase sharedInstance].dbQuque close];
    [MFAPMDataBase sharedInstance].dbQuque = nil;
    [MFAPMDataBase sharedInstance].db = nil;
}

#pragma mark - Add Actions

+ (void)addItems:(NSArray<NSDictionary *> *)itemsArr withTableLimitItemNUM:(NSUInteger)limitItemNUM  complete:(void (^)(BOOL isSuccess))complete{
    if(![itemsArr isKindOfClass:[NSArray class]]
       || itemsArr.count == 0
       || ![[self class] isDataTableCreate]){
        if(complete){
            complete(NO);
        }
        return;
    }
    [[MFAPMDataBase sharedInstance].dbQuque inTransaction:^(FMDatabase *db, BOOL *rollback) {
        @try {
            //插入数据
            for (NSDictionary *itemDict in itemsArr) {
                if(![itemDict isKindOfClass:[NSDictionary class]] || itemsArr.count == 0){
                    continue;
                }
                NSString *paramStr = [MFAPMUtility convertJSONStringFromObject:itemDict] ? : @"";
                [db executeUpdateWithFormat:kMFAPMDataBaseInsertSQL, itemDict[@"timestamp"], itemDict[@"eventType"], paramStr];
            }
            
            //按照timestamp时间戳进行排序后，进行超限数据的移除操作
            NSUInteger itemsCount = [db intForQuery:kMFAPMDataBaseQueryCountSQL];
            NSInteger countOfItemToRemove = itemsCount - limitItemNUM;
            //移除前面超限的数据
            if(countOfItemToRemove > 0){
                [db executeUpdateWithFormat:kMFAPMDataBaseDeletePreNUMItemSQL,@(countOfItemToRemove), @(countOfItemToRemove)];
            }
        } @catch (NSException *exception) {
            *rollback = YES;
        } @finally {
            if(complete){
                complete(!(*rollback));
            }
        }
    }];
}

#pragma mark - Query Actions

+ (NSArray<NSDictionary *> *)queryAllItemsOrderInAsc:(BOOL)isAsc AndDeleteAllData:(BOOL)isDeleteAllData{
    if(![[self class] isDataTableCreate]){
        return nil;
    }
    NSMutableArray *resultArr = [NSMutableArray array];
    
    [[MFAPMDataBase sharedInstance].dbQuque inTransaction:^(FMDatabase *db, BOOL *rollback) {
        @try {
            //是否为升序显示
            NSString *orderWay = isAsc ? @"ASC" : @"DESC";
            
            FMResultSet *resultSet = [db executeQuery:[NSString stringWithFormat:kMFAPMDataBaseQueryAllItemsOrderSQL, orderWay]];
            while ([resultSet next]) {
                NSString *paramStr = [resultSet stringForColumn:@"param"];
                NSDictionary *itemDict = [MFAPMUtility convertDictionaryFromJsonString:paramStr];
                if(itemDict.count > 0){
                    [resultArr addObject:itemDict];
                }
            }
            [resultSet close];
            
            //查询结果后删除全部数据
            if(isDeleteAllData){
                if(![db executeUpdateWithFormat:kMFAPMDataBaseDeleteAllDataSQL]){
                    *rollback = YES;
                }
            }
        } @catch (NSException *exception) {
            *rollback = YES;
        } @finally {
        }
    }];
    return [NSArray arrayWithArray:resultArr];
}

#pragma mark - Setter & Getter

- (NSString *)dbPath{
    if(!_dbPath){
        _dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"MFAPMManager.db"];
    }
    return _dbPath;
}

- (FMDatabase *)db{
    if (!_db) {
        _db = [FMDatabase databaseWithPath:self.dbPath];
    }
    return _db;
}

- (FMDatabaseQueue *)dbQuque{
    if(!_dbQuque){
        _dbQuque = [FMDatabaseQueue databaseQueueWithPath:self.dbPath];
    }
    return _dbQuque;
}

//检查数据表是否被创建，如果并未被创建，则会创建数据表然后将结果返回
+ (BOOL)isDataTableCreate{
    [[MFAPMDataBase sharedInstance].dbQuque inTransaction:^(FMDatabase *db, BOOL *rollback) {
        if(!isTableCreate){
            if(![db executeUpdate:kMFAPMDataBaseCreateSQL]){
                *rollback = YES;
            }else{
                isTableCreate = YES;
            }
        }
    }];
    return isTableCreate;
}

@end
